package com.loveprogrammer.javassist;

/**
 * @ClassName GenerateClazzMethod
 * @Description TODO
 * @Author admin
 * @Date 2023/11/17 16:28
 * @Version 1.0
 */

import com.alibaba.fastjson.JSON;
import javassist.*;
import javassist.bytecode.*;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;
import java.util.Base64;

/**
 * 去修改一个正在执行中的类里面的方法内容。也就是在运行时重新加载类信息
 *
 */
/**
 * 公众号：bugstack虫洞栈
 * 博客栈：https://bugstack.cn - 沉淀、分享、成长，让自己和他人都能有所收获！
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总，旨在为大家提供一个清晰详细的学习教程，侧重点更倾向编写Java核心内容。如果能为您提供帮助，请给予支持(关注、点赞、分享)！
 */
public class GenerateClazzMethod extends ClassLoader {

    public static void main(String[] args) throws Exception {
        // 读取json信息

        // 解析并生成class的byte信息

        ClassPool pool = ClassPool.getDefault();

        CtClass ctClass = pool.makeClass("com.loveprogrammer.javassist.Model03");


        CtClass stringClass = pool.get(String.class.getName());
        // 属性字段
        CtField ctField = new CtField(stringClass, "name", ctClass);
        ctField.setModifiers(Modifier.PRIVATE);

        FieldInfo fieldInfo = ctField.getFieldInfo();
        ConstPool cp = fieldInfo.getConstPool();
        // 方法添加注解
        AnnotationsAttribute methodAnnotationsAttribute = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
        Annotation methodAnnotation = new Annotation("io/swagger/annotations/ApiModelProperty", cp);
        methodAnnotation.addMemberValue("value", new StringMemberValue("名称", cp));
        methodAnnotationsAttribute.setAnnotation(methodAnnotation);
        fieldInfo.addAttribute(methodAnnotationsAttribute);

        ctClass.addField(ctField);

        //为value变量添加set方法
        CtMethod setValue = new CtMethod(CtClass.voidType, "setName", new CtClass[]{stringClass}, ctClass);
        setValue.setModifiers(Modifier.PUBLIC);
        setValue.setBody("{ this.name = $1 ;}");
        ctClass.addMethod(setValue);

        //为value变量添加get方法
        CtMethod getValue = new CtMethod(stringClass, "getName", new CtClass[]{}, ctClass);
        getValue.setModifiers(Modifier.PUBLIC);
        getValue.setBody("{return this.name;}");
        ctClass.addMethod(getValue);


        // 类添加注解
        AnnotationsAttribute clazzAnnotationsAttribute = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
        Annotation clazzAnnotation = new Annotation("io/swagger/annotations/ApiModel", cp);
        clazzAnnotation.addMemberValue("value", new StringMemberValue("测试类", cp));
        clazzAnnotation.addMemberValue("description", new StringMemberValue("测试类的说明", cp));
        clazzAnnotationsAttribute.setAnnotation(clazzAnnotation);
        ctClass.getClassFile().addAttribute(clazzAnnotationsAttribute);

        // 创建无参数构造方法
        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
        ctConstructor.setBody("{}");
        ctClass.addConstructor(ctConstructor);
        // 输出类的内容
        ctClass.writeFile();

        // 测试调用
        byte[] bytes = ctClass.toBytecode();
        String encode = Base64.getEncoder().encodeToString(bytes);
        System.out.println(encode);
        Class<?> clazzNew = new GenerateClazzMethod().defineClass("com.loveprogrammer.javassist.Model03", bytes, 0, bytes.length);
        // Class<?> aClass = getSystemClassLoader().loadClass(clazzNew.getName());

        String json = "{\n" +
                "  \"name\": \"123\"\n" +
                "}";

        Object parsed = JSON.parseObject(json, clazzNew);
        System.out.println(JSON.toJSONString(parsed));


//        // 反射获取 main 方法
//        Method method = clazzNew.getMethod("strToInt", String.class, String.class);
//        Object obj_01 = method.invoke(clazzNew.newInstance(), "1", "2");
//        System.out.println("正确入参：" + obj_01);
//
//        Object obj_02 = method.invoke(clazzNew.newInstance(), "a", "b");
//        System.out.println("异常入参：" + obj_02);
    }

}


